<?php
namespace App\Services\Product;

use App\Events\DeviceStateInfoUpdate;
use App\Events\UserCommand;
use App\Exceptions\DeviceException;
use App\Facades\UserManager;
use App\Facades\DeviceManager;
use App\Utils\DeviceServer;
use Cache;
use Carbon\Carbon;
use DB;
use Exception;
use Illuminate\Foundation\Bus\DispatchesJobs;

class DeviceService
{
	use DispatchesJobs;

	/**
	 * 绑定
	 * @param  string $deviceCode 设备编码
	 */
	public function bind($deviceCode)
	{
		try{
			DB::transaction(function() use ($deviceCode) {
			    $device = DeviceManager::isCreateDeviceRecord($deviceCode);
			    $user = UserManager::getUser();
			    DeviceManager::addUserDevice($user->id, $device->id);
			});
		}catch(Exception $e){
			throw new DeviceException('bind');
		}
	}

	/**
	 * 根据设备号解绑设备
	 * @param  string $deviceCode 设备编码
	 */
	public function unbindByDeviceCode($deviceCode)
	{
		try{
			$user = UserManager::getUser();
			$device = DeviceManager::getDeviceByQuery('code', $deviceCode);
			DeviceManager::deleteUserDeviceByUserIdAndDeviceId($user->id, $device->id);
		}catch(Exception $e){
			throw new DeviceException('unbind');
		}
	}

	/**
	 * 获取设备状态
	 * @return array 	设备状态
	 */
	public function getState()
	{
		$user = UserManager::getUser();
		$device = $this->getDevice($user);
		if(is_null($device)){
			throw new DeviceException('unbind');
		}

		$deviceState = Cache::get($device->code.'state');
		if(count($deviceState)){
			return $deviceState;
		}
	}

	/**
	 * 发送控制命令
	 * @param  string $command    
 	 * @param  string $num        
 	 * @param  string $deviceCode 
	 */
	public function control($command, $num, $deviceCode)
	{
		$this->isOffline($deviceCode);
		$state = Cache::get($deviceCode.'state');
		if($state['state']['decStatus'] == 7 && $command != 'power_on') {
			throw new DeviceException('powerOff');
		}
		event(new UserCommand($command, $num, $deviceCode));
	}

	/**
	 * 
	 * @param  string $command    
	 * @param  string $num        
	 * @param  string $deviceCode 
	 * @return
	 */
	public function getCmd($command, $num, $deviceCode)
	{
		$state = Cache::get($deviceCode.'state');
		
		switch ($command)
		{
			case 'power_on':
				$cmd = DeviceServer::getCmdByte(1, 1, 0);
				break;
			case 'power_off':
				$cmd = DeviceServer::getCmdByte(1, 0, 0);
				break;
			case 'standby':
				$cmd = DeviceServer::getCmdByte(2, 1, 0);
				break;
			case 'standby_cancel':
				$cmd = DeviceServer::getCmdByte(2, 0, 0);
				break;
			case 'wash':
				$cmd = DeviceServer::getCmdByte(3, 1, 0);
				break;
			case 'wash_cancel':
				$cmd = DeviceServer::getCmdByte(3, 0, 0);
				break;
			case 'awaken':
				$cmd = DeviceServer::getCmdByte(8, 1, 0);
				break;
			case 'reset_filter':
				$cmd = DeviceServer::getCmdByte(24, 1<<$num, 0, time());
				break;
			default:
				throw new DeviceException('command');
		}
		return $cmd;
	}

	/**
	 * 获取心跳包
	 * @return
	 */
	public function getSendClockData()
	{
		return DeviceServer::getCmdByte(24, 0, 0, time());
	}

	/**
	 * 处理设备数据
	 * @param  string $dataCmd 
	 * @param  string $fd      
	 * @param  array $data    
	 * @return           
	 */
	public function handle($dataCmd, $fd, $data)
	{
		if ($dataCmd == 0x0001) {
		    $formatData = DeviceServer::dataFormat($data);
		    logger($formatData['state']);
		    
		    if($formatData['state']['decStatus'] != 0){
			    event(new DeviceStateInfoUpdate([
										    	'deviceCode' => $formatData['state']['deviceCode'],
												'decStatus' => $formatData['state']['decStatus'],
												'TDS1' => $formatData['state']['TDS1'],
												'TDS2' => $formatData['state']['TDS2'],
												'phValue' => $formatData['state']['phValue'],
												'filter1' => $formatData['filters']['filter1'],
												'filter2' => $formatData['filters']['filter2'],
												'filter3' => $formatData['filters']['filter3'],
												'filter4' => $formatData['filters']['filter4'],
			    							]));
			    
			    $device = DeviceManager::isCreateDeviceRecord($formatData['state']['deviceCode']);
			    
			    //缓存设备数据
			    $this->cacheDeviceData($formatData, $fd, $data);
			    
			    $this->isSaveDeviceData($formatData, $device->id);
		    }
        }
	}

	/**
	 * 缓存设备相关信息
	 * @param   $formatData 
	 * @param   $fd         
	 * @param   $data       
	 * @return              
	 */
	public function cacheDeviceData($formatData, $fd, $data)
	{
		$expiresAt = Carbon::now()->addMinutes(env('CACHE_DEVICE_DATA'));
		//缓存设备连接 fd
		Cache::put($formatData['state']['deviceCode'].'fd', $fd, $expiresAt);
		//缓存设备数据
		Cache::put($formatData['state']['deviceCode'].'state', $formatData, $expiresAt);
		//缓存设备码二进制数据
		// Cache::put($formatData['state']['deviceCode'].'BinDeviceCode', substr($data, strlen($data) - 10, 8), $expiresAt);
	}

	/**
	 * 存储记录
	 * @param   $formatData 
	 * @return
	 */
	public function isSaveDeviceData($formatData, $deviceId)
	{
		if(!Cache::has($formatData['state']['deviceCode'].'record') && !in_array($formatData['state']['decStatus'], [2, 4, 8])){
			$this->saveDeviceData($formatData, $deviceId);
			Cache::put($formatData['state']['deviceCode'].'record', 1, Carbon::now()->addMinutes(60*24));
		}else if($formatData['state']['decStatus'] == 4 && !Cache::has($formatData['state']['deviceCode'].'recordHydropenia')){
			$this->saveDeviceData($formatData, $deviceId);
			Cache::put($formatData['state']['deviceCode'].'recordHydropenia', 1, Carbon::now()->addMinutes(60*24));
		}else if($formatData['state']['decStatus'] == 2 && !Cache::has($formatData['state']['deviceCode'].'recordOverhaul')){
			$this->saveDeviceData($formatData, $deviceId);
			Cache::put($formatData['state']['deviceCode'].'recordOverhaul', 1, Carbon::now()->addMinutes(60*24));
		}else if($formatData['state']['decStatus'] == 8 && !Cache::has($formatData['state']['deviceCode'].'leakage')){
			$this->saveDeviceData($formatData, $deviceId);
			Cache::put($formatData['state']['deviceCode'].'leakage', 1, Carbon::now()->addMinutes(60*24));
		}
	}

	/**
	 * 
	 * @param  array $formatData 
	 * @param  integer $deviceId   
	 * @return              
	 */
	public function saveDeviceData($formatData, $deviceId)
	{
		$createData = [
			'device_id' => $deviceId,
			'TDS1' => $formatData['state']['TDS1'],
			'TDS2' => $formatData['state']['TDS2'],
			'ph_value' => $formatData['state']['phValue'],
			// 'water_quality' => $formatData['state']['waterQuality'],
			'dec_status' => $formatData['state']['decStatus'],
			// 'filter_cnt1' => $formatData['filters']['filterCnt1'],
			// 'filter_cnt2' => $formatData['filters']['filterCnt2'],
			// 'filter_cnt3' => $formatData['filters']['filterCnt3'],
			// 'filter_cnt4' => $formatData['filters']['filterCnt4'],
			// 'filter_set1' => $formatData['filters']['filterSet1'],
			// 'filter_set2' => $formatData['filters']['filterSet2'],
			// 'filter_set3' => $formatData['filters']['filterSet3'],
			// 'filter_set4' => $formatData['filters']['filterSet4'],
			'filter1' => $formatData['filters']['filter1'],
			'filter2' => $formatData['filters']['filter2'],
			'filter3' => $formatData['filters']['filter3'],
			'filter4' => $formatData['filters']['filter4'],
			// 'water_cnt' => $formatData['state']['waterCnt'],
			// 'water_time' => $formatData['state']['waterTime'],
		];
		DeviceManager::addDeviceRecord($createData);
	}

	/**
	 * 
	 * @param  integer $fd 
	 * @return      
	 */
	public function sendClock($fd)
	{
		event(new UserCommand('send_clock', null, null, $fd));
	}

	/**
	 * 是否离线
	 * @param  string  $deviceCode 
	 * @return boolean             
	 */
	public function isOffline($deviceCode)
	{
		$fd = Cache::get($deviceCode.'fd');
		$fds = Cache::get('fds');
		if(is_null($fd) || is_null($fds) || !in_array($fd, $fds)) {
			Cache::forget($deviceCode.'state');
			throw new DeviceException('notConnect');
		}
	}

	/**
	 * 获取设备对象
	 * @param  string  $type 
	 * @param  User $user 
	 * @return        
	 */
	public function getDevice($user = null)
	{
		if(is_null($user)) {
			$user = UserManager::getUser();
		}
		$deviceId = $user->userDevices->pluck('device_id')->first();
		$device = DeviceManager::getDeviceByQuery('id', $deviceId);

		return $device;
	}

	/**
	 * 获取设备记录列表
	 * @param  string $deviceCode 
	 * @param  integer $status     
	 * @return              
	 */
	public function getDeviceRecordLlist($deviceCode, $status)
	{
		$deviceRecordsBuilder = DeviceManager::getDeviceRecordsBuilderOrderByCreatedAtDesc($deviceCode, $status);
		$deviceRecordsBuilder->with(['device' => function($query){
            $query->with(['userInfos' => function($query){
                $query->select('name', 'phone');
            }])->select('id', 'code');
        }])->select([
        			'device_id',
			        'TDS1',
			        'TDS2',
			        'ph_value',
			        'dec_status',
			        'filter1',
			        'filter2',
			        'filter3',
			        'filter4',
			        'created_at',
			        ]);
		return $deviceRecordsBuilder->paginate(15);
	}

	/**
	 * 根据 id 获取设备记录列表
	 * @param integer  $deviceId 
	 * @param integer  $status   
	 * @return            
	 */
	public function getDeviceRecordsByDeviceId($deviceId, $status)
	{
		$deviceRecordsBuilder = DeviceManager::getDeviceRecordsByDeviceIdAndStatus($deviceId, $status);
		return $deviceRecordsBuilder->with(['device']);
	}

}